package com.cheng.admin.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheng.admin.constant.Constants;
import com.cheng.admin.dao.InviteMapper;
import com.cheng.admin.model.Invite;
import com.cheng.admin.model.Order;
import com.cheng.admin.model.UnitPrice;
import com.cheng.admin.service.InviteService;
import com.cheng.admin.service.UnitPriceService;
import com.cheng.common.config.WeChatKeys;
import com.cheng.common.constants.RedisKey;
import com.cheng.common.domain.BaseSearchVO;
import com.cheng.common.exception.CustomException;
import com.cheng.system.model.User;
import com.cheng.system.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.TransferModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户钱包（总金额在用户表） 服务实现类
 * </p>
 *
 * @author 起凡
 * @since 2022-01-17
 */
@Service
@Slf4j
public class InviteServiceImpl extends ServiceImpl<InviteMapper, Invite> implements InviteService {
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    WeChatKeys weChatKeys;
    @Autowired
    UserService userService;
    @Autowired
    UnitPriceService unitPriceService;
    @Autowired
    HttpServletRequest request;

    /**
     * 提交提现审核
     */
    @Override
    public boolean withdrawal(BigDecimal money) {
        // 没有删掉这个key会导致后面无法提现
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisKey.WITHDRAWAL_KEY + StpUtil.getLoginIdAsString(), 1, 60, TimeUnit.SECONDS);
        if (flag) {
            if (money.compareTo(BigDecimal.valueOf(20)) < 0
                    || money.compareTo(BigDecimal.valueOf(200)) > 0) {
                throw new CustomException("单笔提现金额不大于200,不小于20元");
            }
            // 检查总额是否足够
            User user = userService.getById(StpUtil.getLoginIdAsLong());
            if (user.getTotalMoney().compareTo(money) < 0) {
                throw new CustomException("余额不足");
            }
            // 提交提现记录
            Invite invite = new Invite();
            invite.setAmount(BigDecimal.ZERO.subtract(money)).setType(Constants.INVITE_TYPE_WITHDRAWAL)
                    .setStatus(Constants.INVITE_WITHDRAWAL_STATUS_WAITING);
            save(invite);
            return true;
        }
        throw new CustomException("60秒内请勿重复提现");
    }

    /**
     * 提现通过
     */
    @Override
    @Transactional
    public boolean check(Long id) {
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisKey.CHECK_WITHDRAWAL_KEY + StpUtil.getLoginIdAsString(), 1, 60, TimeUnit.SECONDS);
        if (flag) {
            Invite invite = getById(id);
            //检查余额
            User user = userService.getById(invite.getUserId());
            if (user.getTotalMoney().compareTo(invite.getAmount()) < 0) {
                throw new CustomException("用户余额不足");
            }
            String ip = IpKit.getRealIp(request);
            if (StringUtils.isBlank(ip)) {
                ip = "127.0.0.1";
            }
            WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
            Map<String, String> params = TransferModel.builder()
                    .mch_appid(weChatKeys.getAppId())
                    .mchid(weChatKeys.getMchId())
                    .nonce_str(WxPayKit.generateStr())
                    .partner_trade_no(invite.getId().toString())
                    .openid(user.getOpenId())
                    .check_name("NO_CHECK")
                    .amount("" + invite.getAmount().multiply(BigDecimal.valueOf(100)).intValue())
                    .desc("飞鸽邮筒提现")
                    .spbill_create_ip(ip)
                    .build()
                    .createSign(weChatKeys.getApiKey(), SignType.MD5, false);

            // 提现
            String transfers = WxPayApi.transfers(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
            log.info("提现结果:" + transfers);
            Map<String, String> map = WxPayKit.xmlToMap(transfers);
            String returnCode = map.get("return_code");
            String resultCode = map.get("result_code");
            if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) {
                userService.minusUserMoney(invite.getAmount(), user.getUserId());
                invite.setStatus(Constants.INVITE_WITHDRAWAL_STATUS_CHECK);
                updateById(invite);
                // 提现成功
                return true;
            } else {
                // 提现失败
                throw new CustomException("提现失败");
            }
        }
        throw new CustomException("60秒内请勿重复提现");
    }

    /**
     * 提现拒绝
     */
    @Override
    public boolean refuse(Long id, String reason) {
        update(Wrappers.<Invite>lambdaUpdate().set(Invite::getRemark, reason)
                .set(Invite::getStatus, Constants.INVITE_WITHDRAWAL_STATUS_REFUSE).eq(Invite::getId, id));
        return true;
    }

    /**
     * @param order 中的id
     * @param order 中的最终价格
     * @return boolean
     */
    @Override
    public boolean extract(Order order) {

        Invite invite = getOne(Wrappers.<Invite>lambdaQuery().eq(Invite::getType, Constants.INVITE_TYPE_INVITE)
                .eq(Invite::getInviteeId, StpUtil.getLoginIdAsLong()));
        if (invite != null) {
            // 查询抽成百分比
            UnitPrice unitPrice = unitPriceService.getOne(Wrappers.<UnitPrice>lambdaQuery().eq(UnitPrice::getType, Constants.UNIT_PRICE_EXTRACT));
            Invite orderExtract = new Invite();
            orderExtract.setUserId(invite.getUserId()).setInviteeId(StpUtil.getLoginIdAsLong()).setOrderId(order.getId())
                    .setType(Constants.INVITE_TYPE_EXTRACT);
            //计算抽成
            BigDecimal award = order.getFinalPrice().multiply(unitPrice.getFirstPrice());
            orderExtract.setAmount(award);
            save(orderExtract);
            //增加用户推广总额
            userService.plusUserMoney(award, invite.getUserId());
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public boolean join(Long invitorId) throws Exception {
        try {
            log.info(invitorId.toString());
            User user = userService.getById(StpUtil.getLoginIdAsLong());
            LocalDateTime localDateTime = LocalDateTime.now().minusMinutes(10);
            log.info(user.toString());
            //如果用户是10分钟内刚刚创建的
            if (localDateTime.isBefore(user.getCreateTime())) {
                Invite one = getOne(Wrappers.<Invite>lambdaQuery().eq(Invite::getUserId, invitorId).eq(Invite::getInviteeId, user.getUserId()));
                //如果没被邀请过
                if (one != null) {
                    throw new CustomException("该用户已被邀请");
                }
                // 查看邀请了多少人，根据此来获得相应的佣金。邀请的越多，每次邀请得到的钱越少（看具体配置）
                List<Invite> list = list(Wrappers.<Invite>lambdaQuery().eq(Invite::getUserId, invitorId).eq(Invite::getType, Constants.INVITE_TYPE_INVITE));
//           // +1代表刚刚被邀请的用户
                Integer inviteCount = list.size() + 1;
                log.info(inviteCount.toString());
//           // first<=inviteCount<end
                UnitPrice uniteInvite = unitPriceService.getOne(Wrappers.<UnitPrice>lambdaQuery().le(UnitPrice::getFirst, inviteCount).gt(UnitPrice::getEnd, inviteCount).eq(UnitPrice::getType, Constants.UNIT_PRICE_INVITE));
                log.info(uniteInvite.toString());
                // 增加邀请记录
                Invite invite = new Invite();
                invite.setUserId(invitorId).setInviteeId(user.getUserId()).setAmount(uniteInvite.getRenewalPrice())
                        .setType(Constants.INVITE_TYPE_INVITE);
                save(invite);
                // 增加总金额
                userService.plusUserMoney(invite.getAmount(), invitorId);
                return true;
            }
            throw new CustomException("该用户不是新用户");
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("邀请错误");
        }
    }

    @Override
    public PageInfo<Invite> list(BaseSearchVO searchVO) {
        PageHelper.startPage(searchVO.getPageNum(), searchVO.getPageSize());
        LambdaQueryWrapper<Invite> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(searchVO.getType())) {
            queryWrapper.eq(Invite::getType, searchVO.getType());
        } else {
            queryWrapper.ne(Invite::getType, Constants.INVITE_TYPE_WITHDRAWAL);
        }
        if (searchVO.getUserId() != null) {
            queryWrapper.eq(Invite::getUserId, searchVO.getUserId());
        }
        if (searchVO.getStartTime() != null) {
            queryWrapper.ge(Invite::getCreateTime, searchVO.getStartTime());
        }
        if (searchVO.getEndTime() != null) {
            queryWrapper.le(Invite::getCreateTime, searchVO.getEndTime());
        }
        queryWrapper.orderByDesc(Invite::getCreateTime);
        List<Invite> list = list(queryWrapper);
        PageInfo<Invite> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<Invite> listForBack(BaseSearchVO searchVO) {
        PageHelper.startPage(searchVO.getPageNum(), searchVO.getPageSize());
        LambdaQueryWrapper<Invite> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(searchVO.getType())) {
            queryWrapper.eq(Invite::getType, searchVO.getType());
        }
        if (searchVO.getUserId() != null) {
            queryWrapper.eq(Invite::getUserId, searchVO.getUserId());
        }
        if (searchVO.getStartTime() != null) {
            queryWrapper.ge(Invite::getCreateTime, searchVO.getStartTime());
        }
        if (searchVO.getEndTime() != null) {
            queryWrapper.le(Invite::getCreateTime, searchVO.getEndTime());
        }
        queryWrapper.orderByDesc(Invite::getCreateTime);
        List<Invite> list = list(queryWrapper);
        PageInfo<Invite> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }
}
